package com.copy;

import java.text.MessageFormat;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;


/**
 * Created by sxl4287 on 16/8/16.
 * Email : sxl4287@arcsoft.com
 */
public class BaseSysParams implements Cloneable {
    private static final String baseParameter = "'{'\"code\":{0,number,#},\"clientOs\":\"{1}\",\"osVersion\":\"{2}\",\"appKey\":\"{3}\",\"clientVersion\":\"{4}\",\"country\":\"{5}\",\"language\":\"{6}\",\"imei\":\"{7}\",\"model\":\"{8}\",\"channel\":\"{9}\",\"userTags\":\"{10}\",\"apiVer\":\"{11}\",\"timeStamp\":{12,number,#}";
    private static final String userExtra = ",\"userId\":{0,number,#},\"token\":\"{1}\"";
    private static final String identifierExtra = ",\"identifier\":\"{0}\",\"value\":\"{1}\"";
    private static final String ends = "}";
    //0 :未初始化;1:有数据;-1:没有数据。避免服务器没有配置数据，每次都要进行一次io
    private volatile static int abTestFlag = 0;
    transient AtomicBoolean isIdle = new AtomicBoolean(true);

    public static volatile String userTags;
    private int apiCode;
    private final String country;
    private final String language;
    private int userId;
    private String token;
    //For AB TEST
    public String identifier;
    public String value;

    private BaseSysParams(int apiCode/*, boolean async*/) {
        this.apiCode = apiCode;
        country = "cn";
        language = "cn-zh";
        if (userTags == null) {
            setUserTags(true);
        }

    }

    public void setApiCode(int apiCode) {
        this.apiCode = apiCode;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        BaseSysParams obj = (BaseSysParams) super.clone();
        obj.isIdle = new AtomicBoolean();
        return obj;
    }

    public static void setUserTags(boolean isVipPurchase) {
        if (isVipPurchase) {
            userTags = "365vip";
        } else {
            userTags = "no_ads";
        }
//        LogUtil.log("xTag", "userTags=" + userTags);
    }


    private String toJsonString() {
        long timestamp = System.currentTimeMillis() / 1000;
        MessageFormat formatter = new MessageFormat(baseParameter);
        String base = formatter.format(new Object[]{apiCode, "aphone", "10", "abc123",
                "v1.2.3", country, language, "miString", "HuaWei",
                "googlePlay", userTags == null ? "" : userTags, "apiV1", timestamp});

        if (null != (token)) {
            formatter.applyPattern(userExtra);
            base += formatter.format(new Object[]{userId, token});
        }
        if (null != (identifier)) {
            formatter.applyPattern(identifierExtra);
            base += formatter.format(new Object[]{identifier, value});
        }
        base += ends;
        return base;
    }

    /**
     * 本方法会阻塞线程，慎用。
     */
    public String toJson() {
        try {
            prepareData(null);
            return toJsonString();
        } finally {
            isIdle.set(true);
        }
    }

    private void prepareData(OnDataArrive onDataArrive) {
        userId = 456;
        token = "456'sToken";

        if (abTestFlag >= 0) {
            identifier = null;
            value = null;
        }

        if (onDataArrive != null) {
            onDataArrive.onArrive(toJsonString());
            isIdle.set(true);
        }

    }

    public static void resetFlag() {
        abTestFlag = 0;
    }

    public interface OnDataArrive {
        void onArrive(String sysParams);
    }

    public static final class BaseParameter {
        private static BaseParameter instance;
        private final AtomicInteger mOrderNumber;
        private final BaseSysParams[] cache = new BaseSysParams[4];
        private static final int RESET_NUM = 15;

        public static BaseParameter getInstance() {
            if (instance == null) {
                synchronized (BaseParameter.class) {
                    if (instance == null) instance = new BaseParameter();
                }
            }
            return instance;
        }

        private BaseParameter() {
            this.mOrderNumber = new AtomicInteger(0);
        }

        public BaseSysParams obtain(int code) {
            int executeCount = 0;
            BaseSysParams result = null;
            do {
                if (executeCount > (cache.length << 1)) break;
                int currentIndex = mOrderNumber.getAndIncrement();
                if (currentIndex > RESET_NUM) mOrderNumber.set(0);
                int index = currentIndex & (cache.length - 1);
                result = cache[index];
                if (result == null) {
                    result = new BaseSysParams(code/*, false*/);
                    cache[index] = result;
                }
                executeCount++;
            } while (!result.isIdle.compareAndSet(true, false));
            if (result != null && !result.isIdle.get()) {
                result.apiCode = code;
            } else {
//                result = cache[0].clone();
                result = new BaseSysParams(code);
            }
            return result;
        }


    }


}
